
const graphHeatmap = {
	blockHeatmap: function(container, content) {

        var sum = function(array) {
            var sum_v = 0;
            for (var i in array) {
                sum_v += array[i];
            }
            return sum_v;
        };

        d3.select("div#" + container).selectAll("*").remove();

        var title_height = 70;
        var max_text_size = 12;
        var correlation_data = content.correlation_data;

        var row_num = correlation_data.length;
        var column_num = correlation_data[0].length;

        var width = content.size.width;
        var height = content.size.height;

        var threshold = content.params.threshold ? content.params.threshold : 0;

        var text_size = {
            "title": "18px",
            "sub_title": "17px",
            "legend_title": "15px",
            "legend": "12px",
            "axis": "12px"
        };

        var color_list = content.color_list;
        var module_data = content.module_data;
        var row_name_width = d3.max(content.rows.map(function(d) {return d.length*4}));

        var legend_width = 90;
        var column_text_num = 0;
        var ifCluster = true;
        for (var i in content.columns) {
            if (content.columns[i].length > column_text_num) {
                column_text_num = content.columns[i].length;
            }
        }

        var raw_text_num = 0;
        for (var i in content.rows) {
            if (content.rows[i].length > raw_text_num) {
                raw_text_num = content.rows[i].length;
            }
        }

        var column_text_length = 16 * column_text_num;
        var columns_height = column_text_length * Math.sin(1.22);
        columns_height = columns_height < 30 ? 30 : columns_height;
        var heatmap_height = height - columns_height - title_height;

        var rect_height = heatmap_height / row_num;
        if (parseInt(rect_height) > max_text_size) {
            var row_text_size = max_text_size;
        } else {
            var row_text_size = parseInt(rect_height);
        }

        // 计算列宽，这就是不知道使用scale的悲剧
        if (raw_text_num > 9) {
            var rows_width = raw_text_num * parseInt(row_text_size * 0.6);
        } else {
            var rows_width = raw_text_num * 17;
        }
        if (width - legend_width - rows_width < 100) {
            rows_width = width - legend_width - 200;
        }

        // 控制色块间隙
        var gap = 0.5;
        var if_gap = content.params.if_gap;
        if_gap === "false" ? gap = 0 : gap = gap;

        // 渐变色
        var start_color = d3.rgb(content.params.start_color);
        var end_color = d3.rgb(content.params.end_color);
        var module_block_width = 50;
        var middle_color = content.params.middle_color ? d3.rgb(content.params.middle_color) : null;
        var heatmap_width = width - (row_name_width + module_block_width)*1.7 - legend_width;
        var rect_width = (heatmap_width / column_num).toFixed(3);

        // 是否在色块中显示对应值
        var show_value = content.params.show_value ? true : false;

        // 如果列名称字符串长度大于列宽，旋转列名
        var column_rotate = false;
        if (column_text_length > rect_width) {
            var column_rotate = true;
        }

        // 获取一般情况下的值域
        var max_value = [];
        var min_value = [];
        for (var i in correlation_data) {
            var temp_max = d3.max(correlation_data[i]);
            var temp_min = d3.min(correlation_data[i]);
            max_value.push(temp_max);
            min_value.push(temp_min);
        }
        max_value = d3.max(max_value);
        min_value = d3.min(min_value);

        // 底下的列文字字高不得小于色块宽度：？？
        if (parseInt(rect_width) > max_text_size) {
            var column_text_size = max_text_size;
        } else {
            var column_text_size = parseInt(rect_width);
        }

        // 色块里的文字字高
        var rect_text_size = row_text_size;
        if (rect_text_size > column_text_size) {
            rect_text_size = column_text_size;
        }
        row_text_size = row_text_size + "px";
        column_text_size = column_text_size + "px";

        // 图例处理
        var heatmap_legend_width = 20;
        var heatmap_legend_posion = {
            x: (row_name_width + module_block_width) * 1.7 + heatmap_width + 40,
            y: (0.5 * heatmap_height) + title_height
        };
        var heatmap_legend_height = 0.5 * heatmap_height;
        var svg = d3.select("div#" + container).append("svg")
            .attr("width", width)
            .attr("height", height)
            .attr("version", 1.1)
            .attr("xmlns", "http://www.w3.org/2000/svg");

        var get_color;
        if (middle_color) {
            get_color = d3.scale.linear()
    			.domain([-1, 0, 1])
                .range([start_color, middle_color, end_color]);
        } else {
    		get_color = d3.scale.linear().domain([-1, 1]).range([start_color, end_color]);
        }

        var defs = svg.append("defs");
        var filter = defs.append("filter").attr("id", "f1").attr("x", "0").attr("y", "0");
        filter.append("feOffset").attr("result", "offOut").attr("in", "SourceGraphic").attr("dx", 0).attr("dy", 0);
        filter.append("feColorMatrix").attr("result", "matrixOut").attr("in", "offOut").attr("type", "matrix").attr("values", "0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 4 0");
        filter.append("feGaussianBlur").attr("result", "blurOut").attr("in", "matrixOut").attr("stdDeviation", "3");
        filter.append("feBlend").attr("in", "SourceGraphic").attr("in-2", "blurOut").attr("mode", "normal");

        function sprintf(text, arr) {
            var i = 0;
            return text.replace(/\$S/g, function () {
                return (i < arr.length) ? arr[i++] : "";
            });
        }
        var colorStops = [
          '<stop offset="0%" stop-color="$S"></stop>',
          '<stop offset="50%" stop-color="$S"></stop>',
          '<stop offset="100%" stop-color="$S"></stop>'
          ];
        if(!middle_color){
            colorStops = colorStops[0] + colorStops[2];
            colorStops = sprintf(colorStops, [start_color, end_color]);
        }else{
            colorStops = sprintf(colorStops.join(''), [start_color, middle_color, end_color]);
        };

        defs.append('linearGradient')
          .attr({
            id: 'horizontalyToRight',
            x1: "0%",
            y1: "0%",
            x2: "100%",
            y2: "0%"
          })
          .html(colorStops);

        var dstartX, dstartY;
        var dragListener = d3.behavior.drag()
            .on("dragstart", function() {
                dstartX = d3.mouse(this)[0];
                dstartY = d3.mouse(this)[1];
            })
            .on("drag", function() {
                d3.select(this).attr("transform", "translate(" + (d3.event.x - dstartX) + ", " + (d3.event.y - dstartY) + ")");
            });

        if(content.params.disableDrag){
            dragListener = function(ele){return false;};
        }

        var title_height = 82;
        var title_rect = svg.append("g")
                        .attr("class", 'block-title')
                        .attr("height", title_height/2)
                        .attr("transform", "translate(0, 50)");

        title_rect.append("text")
            .attr("class", "title")
            .attr("font-size", "20px")
            .attr("text-anchor", "middle")
            .attr("x", function() {
                return width*0.48 - this.getComputedTextLength() / 2;
            })
            .text(content.params.title)
            .call(dragListener);

        var nonius_scale = 6;
        var nonius_path = "M" + 1 * nonius_scale + " " + " 0 " + "L" + 2 * nonius_scale + " 0 " + "L" + 2 * nonius_scale + " " + 2 * nonius_scale + " L" + nonius_scale + " " + 2 * nonius_scale + " L0 " + nonius_scale + " Z";

        var nonius_y = d3.scale.linear().domain([1, -1]).range([0, heatmap_legend_height]); //modify by qindanhua
        var mouseover_color = d3.rgb(get_color(0.55)).brighter(13);
        var lab_color = d3.lab(mouseover_color);
        lab_color.l = lab_color.l - 5;
        lab_color.a = lab_color.a + 20;
        lab_color.b = lab_color.b - 15;
        mouseover_color = d3.rgb(lab_color);

        var heatmap_legend = svg.append("g").attr("class", "heatmap_legend").attr("id", "hhhhhheat")
            .attr("transform", "translate(" + heatmap_legend_posion.x + ", " + heatmap_legend_posion.y + ")")
            .call(dragListener);

        var linearGradient = heatmap_legend
            .append("linearGradient")
            .attr("id", "linearColor")
            .attr("x1", "0%")
            .attr("y1", "100%")
            .attr("x2", "0%")
            .attr("y2", "0%");
        var stop_start = linearGradient
            .append("stop")
            .attr("offset", "0%")
            .style("stop-color", start_color.toString());
        if (middle_color) {
            var stop_middle = linearGradient
                .append("stop")
                .attr("offset", "50%")
                .style("stop-color", middle_color.toString());
        }
        var stop_end = linearGradient.append("stop").attr("offset", "100%").style("stop-color", end_color.toString());
        var colorRect = heatmap_legend.append("rect")
            .attr("width", heatmap_legend_width).attr("height", heatmap_legend_height).attr("stroke", "black").attr("stroke-width", 0.2).attr("fill", "url(#" + linearGradient.attr("id") + ")");

        var legend_nonius = heatmap_legend.append("path")
            .attr("d", nonius_path)
            .attr("class", "legend-nonius")
            .attr("fill", "#33a3dc")
            .attr("fill-opacity", 0);

        var linear_legend = d3.scale.linear().domain([1, -1]).range([0, heatmap_legend_height]);
        var ticks_num = Math.ceil(heatmap_legend_height / 50);
        var axis = d3.svg.axis().orient("left").scale(linear_legend).ticks(ticks_num).tickSize(3);
        var heatmap_legend_axis = heatmap_legend.append("g").attr("class", "heatmap_legend_axis");
        heatmap_legend_axis
            .attr("font-family", "arial")
            .attr("font-size", text_size.legend)
            .call(axis);

        heatmap_legend_axis.selectAll("g line").attr("fill", function(d) {
            return "none";
        }).attr("stroke", "#77787b").attr("shape-rendering", "crispEdges");
        heatmap_legend_axis.selectAll("path").attr("fill", function(d) {
            return "none";
        }).attr("stroke-width", 0).attr("shape-rendering", "crispEdges");

        var legendGroupScale;
        if(content.params.legendOrient === "TopRight"){

            heatmap_legend.remove();

            var legendGroup = svg.append('g')
                .attr({
                    class: "svg-legend",
                    transform: "translate(" +
                        [heatmap_width + 20, title_height] + ")"
                });

            var pointerDown = "M0 0 " +
                "L" + nonius_scale    + " " + -nonius_scale     + " " +
                "L" + nonius_scale    + " " + -2 * nonius_scale + " " +
                "L" + (-nonius_scale) + " " + -2 * nonius_scale + " " +
                "L" + (-nonius_scale) + " " + -nonius_scale     + " Z";

            var legendRectWidth = Math.min(rows_width, 120);
            legendGroup.append('rect')
                .attr({
                    width: legendRectWidth,
                    height: 15,
                    "shape-rendering": "crispEdges",
                    fill: "url(#horizontalyToRight)"
                });

            var legendGroupScale = d3.scale.linear()
                    .domain([-1, 1])
                    .range([0, legendRectWidth]),

                legendGroupAxis = d3.svg.axis()
                    .scale(legendGroupScale)
                    .orient("bottom")
                    .outerTickSize(0)
                    .ticks(5),

                legendAxisGroup = legendGroup.append("g")
                    .attr("transform", "translate(0," + 15 + ")")
                    .call(legendGroupAxis)
                    .call(function(e){
                        e.selectAll("path").attr({
                            fill: "none",
                            stroke: "none"
                        });
                        e.selectAll("line").attr({
                            stroke: "#000",
                            "stroke-width": 1,
                            "shape-rendering": "crispEdges"
                        });
                        e.selectAll("text").attr({
                            "font-family": "arial",
                            "font-size": text_size.legend
                        });

                        var tickGroup = e.selectAll("g");
                        if(tickGroup.size() >= 3){
                            tickGroup.each(function(d, i){
                                if(i > 0 && i < (tickGroup.size() - 1)){
                                    d3.select(this).style("opacity", 0);
                                }
                            });
                        }
                    }),

                legendPointer = legendGroup.append("path")
                    .attr({
                        class: "legend-pointer",
                        d: pointerDown,
                        fill: "#33a3dc",
                        "fill-opacity": 0
                    });
        }

        var heatmap_module_block = svg.append("g").attr("class", "heatmap_module_block")
                .attr("transform", "translate(" + row_name_width + "," + title_height + ")");
        var heatmap_g = svg.append("g").attr("class", "heatmap")
            .attr("transform", "translate(" + (row_name_width + module_block_width)*1.7 + "," + title_height + ")");

        var rect_array = [];

        var rows_g = svg.append("g").attr("class", "row_names")
                    .attr("width", row_name_width)
                    .attr("transform", "translate(" + 0 + "," + title_height + ")");
        var rows = rows_g.selectAll(".rows_names").data(content.rows).enter().append("text")
        .text(function(d) {
            return d;
        })
        .attr("font-family", "arial").attr("font-size", row_text_size).attr("x", 15).attr("y", function(d, i) {
            return (i + 0.5) * rect_height + 0.33 * parseInt(row_text_size);
        });

        var pvalue_data = content.pvalue_data;

        for (var row in correlation_data) {
            var dataBuilded = [];
            var db = [];
            for (var i = 0; i < correlation_data[row].length; i++) {
                row = parseInt(row);
                var dataSingle = {
                    "rowName": content.rows[row],
                    "colName": content.columns[i],
                    "value": correlation_data[row][i],
                    "pvalue": pvalue_data[row][i],
                    "show": correlation_data[row][i],
                    row: row,
                    column: i
                };

                dataBuilded.push(dataSingle);
                db.push({"color": color_list[row], "value":module_data[row]});
            }

            var heatmap_block = heatmap_module_block.selectAll(".heat").data(db);
            var module_block = heatmap_block.enter().append("g").attr("transform", function(d, i) {
                return "translate(" + row_name_width + ", " + row * rect_height + ")";
            });
            module_block.append("rect")
                .attr("width", module_block_width)
                .attr("height", rect_height - gap)
                .attr("stroke", "none")
                .attr("stroke-width", 0)
                .attr("fill", function(d) {
                return d.color;
            });

            module_block.append("text").text(function(d) {
                return d.value;
            }).attr("font-size", "14px")
              .attr("font-family", "arial")
              .attr("text-anchor", "middle")
              .attr("stroke", function(d) {
                 if(d.color.toLowerCase() == "black") {
                    return "white";
                 } else {
                    return "black";
                 }
              })
              .attr("transform", "translate(" + (module_block_width/2) + "," + (rect_height / 2 + rect_text_size / 2) + ")");


            var heatmap = heatmap_g.selectAll(".heat").data(dataBuilded);
            var heatmapRectG = heatmap.enter().append("g").attr("transform", function(d, i) {
                return "translate(" + i * rect_width + ", " + row * rect_height + ")";
            });
            heatmapRectG.append("rect")
                .attr("width", rect_width - gap)
                .attr("height", rect_height - gap)
                .attr("stroke", "none")
                .attr("stroke-width", 0)
                .attr("fill", function(d) {
                     return get_color(d.value);
                })
            .on("mouseover", function(d) {
                d3.select(this)
                .attr("stroke", "black")
                .attr("stroke-width", 2);
                var text = {row: d.rowName,
                    column: d.colName,
                    value: d.show,
                    pvalue: d.pvalue
                };
                var text_length = Math.max(text.row.length, text.column.length, text.value.toString().length);
                text_length = text_length * 20;
                show_tooltip((d.column + 0.5) * rect_width + (row_name_width + module_block_width)*1.7, d.row * rect_height + title_height, text_length, text, get_color(d.value));

                if(content.params.legendOrient === "TopRight"){
                    var moveX = legendGroupScale(d3.select(this).datum().value);
                    svg.select(".legend-pointer").attr({
                        transform: "translate(" + moveX + "0)",
                        "fill-opacity": 1
                    });
                }else{
                    svg.select(".legend-nonius")
                    .attr("transform", "translate(" + heatmap_legend_width + "," + (nonius_y(d.value) - nonius_scale) + ")")
                    .attr("fill-opacity", 1);
                }
            })
            .on("mouseout", function(d) {
                d3.select(this)
                    .attr("stroke", "none")
                    .attr("stroke-width", 0);

                clean_tooltip();

                if(content.params.legendOrient === "TopRight"){
                    svg.select(".legend-pointer").attr("fill-opacity", 0);
                }else{
                    svg.select(".legend-nonius").attr("fill-opacity", 0);
                }
            });
            if (show_value) {
                heatmapRectG.append("text").text(function(d) {
                    return d.value;
                }).attr("font-size", rect_text_size + "px")
                  .attr("font-family", "arial")
                  .attr("text-anchor", "middle")
                  .attr("transform", "translate(" + rect_width / 2 + "," + (rect_height / 2 - 4) + ")");

                heatmapRectG.append("text").text(function(d) {
                    return "(" + d.pvalue + ")";
                }).attr("font-size", rect_text_size + "px")
                  .attr("font-family", "arial")
                  .attr("text-anchor", "middle")
                  .attr("transform", "translate(" + rect_width / 2 + "," + (rect_height - 4) + ")");
            }

        }

        var tooltip_g = '';
        function show_tooltip(x, y, length, text, color) {
            length = Math.max(length, 130);
            length = Math.min(length, 150);

            var tooltip_scale = length / 12;
            var tooltip_high = 74;
            var tooltip_path = "M0 0 L" + 10 + " " + "-10" + " L" + tooltip_scale * 4 + " -10 L" + tooltip_scale * 4 + " -" + tooltip_high + " L-" + tooltip_scale * 4 + " -" + tooltip_high + " L-" + tooltip_scale * 4 + " -10 L-10 -10 z";
            tooltip_g = svg.append("g").attr("class", "tooltip_g").attr("transform", "translate(" + x + "," + y + ")");
            tooltip_g
                .append("path")
                .attr("d", tooltip_path)
                .attr("fill", "#fffef9")
                .attr("fill-opacity", 0.9)
                .attr("filter", "url(#f1)")
                .attr("stroke", color)
                .attr("stroke-width", "1.5");
            var tooltip_text = tooltip_g.append("text").attr("font-family", "arial").attr("font-size", 12 + "px");
            tooltip_text.append("tspan").text(text.column).attr("x", 0 - length / 4).attr("y", 6 - 70).attr("dy","1em");
            tooltip_text.append("tspan").text("corre:" + text.value).attr("x", 0 - length / 4).attr("y", 22 - 70).attr("dy","1em");
            tooltip_text.append("tspan").text("pvalue:" + text.pvalue).attr("x", 0 - length / 4).attr("y", 38 - 70).attr("dy","1em");

        }
        function clean_tooltip(){
            tooltip_g.remove();
        }

        var columns_g = svg.append("g").attr("class", "columns_names").attr("transform", "translate(" + (row_name_width + module_block_width)*1.7 + "," + (title_height + heatmap_height) + ")");
        if (parseInt(rect_width) > 15) {
            var column_text_size = text_size.legend;
        } else {
            var column_text_size = parseInt(rect_width) + "px";
        }
        var columns = columns_g.selectAll(".columns_names").data(content.columns).enter().append("text").text(function(d) {
            return d;
        }).attr("font-family", "arial").attr("font-size", column_text_size).attr("x", function(d, i) {
            if (column_rotate) {
                return (i + 0.5) * rect_width - this.getComputedTextLength();
            } else {
                return (i + 0.5) * rect_width - (this.getComputedTextLength() / 2);
            }
        }).attr("y", 15).attr("transform", function(d, i) {
            if (column_rotate) {
                return "rotate(-70, " + (parseInt(i) + 0.5) * rect_width + ",15)";
            } else {
                return "";
            }
        });

        function max_min_array(array) {
            var max = array[0];
            var min = array[0];
            for (var i in array) {
                if (max < array[i]) {
                    max = array[i];
                }
                if (min > array[i]) {
                    min = array[i];
                }
            }
            return {
                max: max,
                min: min
            };
        }

        var return_chart = {
            svg: svg,
            reSize: function(w, h) {
                var scale_w = w / content.size.width;
                var scale_h = h / content.size.height;
                content.size.width = w;
                content.size.height = h;
                d3.select("div#" + container).selectAll("*").remove();
                tree_heatmap(container, content);
            }
        };
        return return_chart;
    }
};

export default graphHeatmap;